﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tom.Algorithm
{
    // Data structure for real chromosome
    public class GeneticChromReal
    {
        readonly List<double> _Gene;

        public GeneticChromReal(List<double> x)
        {
            _Gene = new List<double>(x);
        }

        public List<double> Gene
        {
            get { return _Gene; }
        }
    }

    // Genetic operation for real type
    public class GeneticOpReal : IGeneticOp<GeneticChromReal>
    {
        int _NDim;
        double _MutationProb;
        Random _Rnd;

        // Constructor(s)
        public GeneticOpReal(int nDim) : this(nDim, new Random()) { }

        public GeneticOpReal(int nDim, Random rnd)
        {
            _NDim = nDim;
            _MutationProb = (1 / (double) nDim);
            _Rnd = rnd;
        }

        // the problem dimension
        public int NDim
        {
            get { return _NDim; }
        }

        // Implements the create instance method
        public GeneticChromReal CreateInstance()
        {
            List<double> x = new List<double>(NDim);
            for (int i = 0; i < NDim; i++)
            {
                x.Add(_Rnd.NextDouble()*NDim);
            }
            return new GeneticChromReal(x);
        }

        // Implements the copy instance method
        public GeneticChromReal CopyInstance(GeneticChromReal chromosome)
        {
            return new GeneticChromReal(chromosome.Gene);
        }

        // Implements the crossover method
        public List<GeneticChromReal> Crossover(GeneticChromReal parent1, GeneticChromReal parent2)
        {
            List<GeneticChromReal> offsprings = new List<GeneticChromReal>(2);

            List<double> list1 = new List<double>(NDim);
            List<double> list2 = new List<double>(NDim);

            int pos = (int)(_NDim * _Rnd.NextDouble());
            for (int i = 0; i < pos; i++)
            {
                list1.Add(parent1.Gene[i]);
                list2.Add(parent2.Gene[i]);
            }
            for (int i = pos; i < NDim; i++)
            {
                list1.Add(parent2.Gene[i]);
                list2.Add(parent1.Gene[i]);
            }

            offsprings.Add(new GeneticChromReal(list1));
            offsprings.Add(new GeneticChromReal(list2));

            return offsprings;
        }

        // Implements the mutation method
        public GeneticChromReal Mutate(GeneticChromReal chromosome)
        {
            List<double> x = new List<double>(chromosome.Gene);
            for (int i = 0; i < NDim; i++)
            {
                if (_Rnd.NextDouble() < _MutationProb) 
                    x[i] += x[i] * (_Rnd.NextDouble() - 0.5) * 2 * 0.1;
            }

            return new GeneticChromReal(x);
        }
    }
}
